import objectTypeEnum from "../enum/objectType.enum"
import { SdkObservable } from "./observable"
import { ClassFactory, copyPosition, isSamePoint } from "./utils"
class PointerSubFactory {
  create(e, t) {
    return t.onChanged(() => e.onChanged())
  }
}

class ObservablePointer {
  colliderTypes: any
  ZERO: any
  tempVec: any
  _data: { position: { x: number; y: number; z: number }; normal: { x: number; y: number; z: number }; object: string; floorId: any; floorIndex: any }
  constructor(e, t) {
    this.colliderTypes = t
    this.ZERO = new e.Vector3(0, 0, 0)
    this.tempVec = new e.Vector3()
    this._data = {
      position: { x: 0, y: 0, z: 0 },
      normal: { x: 0, y: 0, z: 0 },
      object: objectTypeEnum.NONE,
      floorId: void 0,
      floorIndex: void 0
    }
  }
  get data() {
    return this._data
  }
  equals(e) {
    const t = 0.00001,
      o = e.data.position,
      n = this._data.position,
      r = e.data.normal,
      a = this._data.normal
    return isSamePoint(o, n, t) && isSamePoint(r, a, t) && e.data.object === this._data.object
  }
  update(e, t, o, n) {
    const r = e.hit
    r
      ? (copyPosition(this._data.position, r.point),
        copyPosition(this._data.normal, r.face.normal),
        (this._data.floorId = void 0),
        r.object instanceof this.colliderTypes.ModelColliderTarget
          ? ((this._data.object = objectTypeEnum.MODEL),
            (this._data.floorId = ((e, t, o, n, r) => {
              let a
              if (
                (e => {
                  const { object: t } = e
                  return "object" == typeof t && "floorId" in t
                })(e)
              )
                return (a = t.getFloor(e.object.floorId)), a.index
              r.copy(e.point)
              const s = n.meshSubGroupsFromPoint(r)
              if (!s.length) return
              const { meshGroup: i, meshSubgroup: d } = s[0],
                c = o.getByMeshSubgroup(i, d)
              if (!c) return
              return (a = t.getFloor(c.floorId)), a.index
            })(r, t, o, n, this.tempVec)))
          : r.object instanceof this.colliderTypes.PinHeadMesh || r.object instanceof this.colliderTypes.InstancedPinHeads
          ? (this._data.object = objectTypeEnum.TAG)
          : r.object instanceof this.colliderTypes.PuckCollider
          ? (this._data.object = objectTypeEnum.SWEEP)
          : (this._data.object = objectTypeEnum.UNKNOWN))
      : (copyPosition(this._data.position, this.ZERO),
        copyPosition(this._data.normal, this.ZERO),
        (this._data.object = objectTypeEnum.NONE),
        (this._data.floorId = void 0)),
      (this._data.floorIndex = this._data.floorId)
  }
  copy(e) {
    copyPosition(this._data.position, e.data.position)
    copyPosition(this._data.normal, e.data.normal)
    this._data.object = e.data.object
    this._data.floorId = e.data.floorId
    this._data.floorIndex = e.data.floorIndex
  }
}
export default {
  Colliders: sdk => {
    sdk.addEnumToInterface({ namespace: "Pointer", name: "Colliders", values: objectTypeEnum })
  },
  intersection: (sdk, THREE, exportOBJ, dependencies) => {
    const observable = SdkObservable.create(dependencies, new PointerSubFactory(), new ClassFactory(ObservablePointer, THREE, exportOBJ))
    sdk.addObservableToInterface({ namespace: "Pointer", name: "intersection" }, observable)
  }
}
